package {
	import Box2D.Collision.Shapes.b2CircleDef;
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Collision.b2AABB;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2World;
	
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.media.Camera;
	import flash.media.Video;
	import flash.utils.ByteArray;
	
	import org.libspark.flartoolkit.core.FLARCode;
	import org.libspark.flartoolkit.core.param.FLARParam;
	import org.libspark.flartoolkit.core.raster.rgb.FLARRgbRaster_BitmapData;
	import org.libspark.flartoolkit.core.transmat.FLARTransMatResult;
	import org.libspark.flartoolkit.core.types.FLARDoublePoint3d;
	import org.libspark.flartoolkit.detector.FLARSingleMarkerDetector;
	import org.libspark.flartoolkit.pv3d.FLARBaseNode;
	import org.libspark.flartoolkit.pv3d.FLARCamera3D;
	import org.papervision3d.Papervision3D;
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.core.math.Matrix3D;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.BitmapMaterial;
	import org.papervision3d.materials.ColorMaterial;
	import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.objects.primitives.Sphere;
	import org.papervision3d.render.LazyRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;
	
	import teleranek.text.*;
	import teleranek.util.*;
	
	[SWF(frameRate="31", width="640", height="480", backgroundColor="0x000000")]
	public class pdwGraf extends Sprite
	{
		/* this file contains distortion info for your cam. Generated by calib_camera2 app */
		[Embed(source="res/camera_para.dat", mimeType="application/octet-stream")]
		private var CamParams:Class;
		
		/* generated pattern file */
		[Embed(source="res/mikko.pat", mimeType="application/octet-stream")]
		private var MarkerPattern:Class;
		
		private var camParams:FLARParam;
		private var markerPattern:FLARCode;
		private var raster:FLARRgbRaster_BitmapData;
		private var detector:FLARSingleMarkerDetector;
		/* flar pv3d thingies*/
		private var trans:FLARTransMatResult;
		private var mainContainer:FLARBaseNode;
		private var smallmatrix:Matrix;
		
		private var cam:Camera;
		private var vid:Video;
		/* this is camera view capture */
		private var cameraCap:BitmapData;
		
		/*pv3d vars*/
		private var renderer:LazyRenderEngine;
		private var light:PointLight3D;
		private var cube:Cube;
		private var projectionMtx:Matrix3D;
		
		private var physCube:b2Body;
		private var world:b2World;
		
		private const PSCALE:Number = 20;
		public static const DETECTOR_WIDTH:int = 320//480;
		public static const DETECTOR_HEIGHT:int = 240//360;
		public static const CAM_WIDTH:int = 320;
		public static const CAM_HEIGHT:int = 240;
		public static var fps:FPS;
		
		public function pdwGraf()
		{
			Papervision3D.PAPERLOGGER = null;
			stage.scaleMode = StageScaleMode.NO_SCALE;
        	stage.align = StageAlign.TOP_LEFT;
        	
        	/* matrix for scalin bitmap from camera*/
        	smallmatrix = new Matrix();
			var sx:Number = DETECTOR_WIDTH / CAM_WIDTH;
			var sy:Number = DETECTOR_HEIGHT / CAM_HEIGHT;
			smallmatrix.scale( sx, sy );
        	
			/* load params from param file */
			camParams = new FLARParam();
			camParams.loadARParam( ByteArray(new CamParams()) );
			
			/* load marker */
			markerPattern = new FLARCode(16, 16);
			markerPattern.loadARPatt( new MarkerPattern() );
			
			/* setup cam. 30 fps and 640x480 are important for detector to work, but... optimise!!! :D */
			cam = Camera.getCamera();
			cam.setMode( CAM_WIDTH, CAM_HEIGHT, 30);
			vid = new Video();
			vid.width = CAM_WIDTH;
			vid.height = CAM_HEIGHT;
			vid.attachCamera(cam);
			addChild(vid);
			
			cameraCap = new BitmapData( DETECTOR_WIDTH, DETECTOR_HEIGHT, false, 0 );
			raster = new FLARRgbRaster_BitmapData( cameraCap );
			detector = new FLARSingleMarkerDetector( camParams, markerPattern, 80);
			trans = new FLARTransMatResult(); /* <- this transformation mtx tells us how the object is transformed by us in camera */

			initpv3D();
			initPhys();
			
			// my superstuff
			addChild( fps = new FPS( 0xffffff ) );
			addEventListener( Event.ENTER_FRAME, onFrame );
		}
		
		private function initPhys():void{
			var bounds:b2AABB = new b2AABB();
			var wallBd:b2BodyDef = new b2BodyDef();
			var wallSd:b2PolygonDef = new b2PolygonDef();
			var wallB:b2Body;			
			bounds.lowerBound.Set( -1000/PSCALE, -1000/PSCALE );
			bounds.upperBound.Set( 2000/PSCALE , 2000/PSCALE );
			world = new b2World( bounds , new b2Vec2( 0,15 ) , true );
			
			/*walls*/
			wallBd.position.Set( CAM_WIDTH/PSCALE/2, 1.2*CAM_HEIGHT/PSCALE );
			wallSd.SetAsBox((CAM_WIDTH+200)/PSCALE, 100/PSCALE);
			wallSd.friction = 0.3;
			wallB = world.CreateStaticBody(wallBd);
			wallB.CreateShape(wallSd);
			wallB.SetMassFromShapes();
			
			/*paletken*/
			wallBd.position.Set( 0, 0 );
			wallSd.SetAsBox( 80/PSCALE , 10/PSCALE );
			wallSd.friction = 0.3;
			physCube = world.CreateStaticBody( wallBd );
			physCube.CreateShape( wallSd );
			physCube.SetMassFromShapes();
			
			/*ball*/
			var bodyDef:b2BodyDef;
			var shapeDef:b2CircleDef;
			var imgBody:b2Body;
			var sphere:Sphere = new Sphere( new FlatShadeMaterial(light) , 20 );
			sphere.x = -300; sphere.y = 300; sphere.z = 1000;
			renderer.scene.addChild( sphere );
			//mainContainer.addChild( sphere );
			bodyDef = new b2BodyDef();
			bodyDef.position.x = ( sphere.x ) / PSCALE;
			bodyDef.position.y = ( -( sphere.y - CAM_HEIGHT ) ) / PSCALE;
			bodyDef.userData = sphere;
			shapeDef = new b2CircleDef();
			shapeDef.radius = 20/PSCALE;
			shapeDef.density = 1.0;
			shapeDef.friction = 0.3;
			shapeDef.restitution = 0.2;
			imgBody = world.CreateDynamicBody( bodyDef );
			imgBody.CreateShape( shapeDef );
			imgBody.SetMassFromShapes();
			
			var dbgDraw:b2DebugDraw = new b2DebugDraw();
			var dbgSprite:Sprite = new Sprite();
			addChild(dbgSprite);
			dbgDraw.m_sprite = dbgSprite;
			dbgSprite.x = 400;
			dbgSprite.y = 100;
			dbgDraw.m_drawScale = 5;
			dbgDraw.m_fillAlpha = 0.3;
			dbgDraw.m_lineThickness = 1.0;
			dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
			world.SetDebugDraw(dbgDraw);
			
		}
	/*
			####	pv3d init stuff    ####
	*/		
		private function initpv3D():void{
			/* pv3d cam3d is now FLAR cam3d */
			var cam3D:Camera3D = new FLARCamera3D( camParams ); 
			var scene:Scene3D = new Scene3D();
			
			
			mainContainer = new FLARBaseNode();
			scene.addChild( mainContainer );
			var view:Viewport3D = new Viewport3D( vid.width, vid.height );
			view.scaleX = view.scaleY = 2*(CAM_WIDTH/DETECTOR_WIDTH);
			renderer = new LazyRenderEngine( scene , cam3D , view );
			
			
			/* pv3d objects setup */
			light = new PointLight3D();
			light.x = 1000;
			light.y = 1000;
			light.z = -1000;
			
			var fsh:FlatShadeMaterial = new FlatShadeMaterial(light);
			var bmp:BitmapData = new BitmapData( 64 , 64 , false , 0x00ff00 );
			var pdw12txt:txter = new txter( 0,0 , "PDW 12" , 16, 0xff0000 );
			bmp.draw( pdw12txt );
			var cubeMaterialList:MaterialsList = new MaterialsList( { bottom:new ColorMaterial(0),left:fsh,right:fsh,top:fsh,front:new BitmapMaterial(bmp),back:fsh  } );
			cube = new Cube( cubeMaterialList , 80, 10, 80 );
			//cube.z += 15;
			mainContainer.addChild( cube );
			addChild( view );
		}
		
		private function onFrame( evt:Event ):void{
			cameraCap.draw(vid , smallmatrix , null , null , null , true );
			/*      this chex whether marker found          this is the confidence of our findingz          
			                |                                          |
			               \/                                         \/   */
			if ( (detector.detectMarkerLite(raster, 90) && detector.getConfidence() > 0.5 ) )
			{
				
				/* get transf mtx of our marker in space */
				detector.getTransformMatrix( trans );
				/* rotates and translates everything according to mtx*/
				mainContainer.setTransformMatrix( trans );
				var rot:FLARDoublePoint3d = detector.angle;
				//mainContainer.x = mainContainer.x*2
				//mainContainer.y = mainContainer.y*2;
				//mainContainer.z = mainContainer.z*0.5;
				
				//trace( String( rot.x ) + "," + String( rot.y ) + ", " + String( rot.z ) );
				//throw( new ArgumentError("spierd") );
				physCube.SetXForm( new b2Vec2( mainContainer.x/PSCALE , -mainContainer.y/PSCALE  ) , rot.z/5 );
				/* we render only if we moved somthing, so this cmd is inside this if  condition */
				renderer.render();
			}
			
			/* refreshin of kryska*/
			
			
			/* refreshn' of sphere position */
			var body:b2Body = world.m_bodyList;
			body.m_userData.x = body.GetPosition().x*PSCALE;
			body.m_userData.y = CAM_HEIGHT - body.GetPosition().y*PSCALE;
			body.m_userData.rotationZ = body.GetAngle();
			world.Step( 1/30 , 10 );
			//renderer.render();
		}
	}
}
